#include "PSORunner.h"
#include <time.h>

PSORunner::PSORunner(double weight, double c1, double c2, int iterNum, CoverageTable *ct)
	:Runner(iterNum,ct)
{
	accelerator=new Accelerate(weight, c1, c2);
	move=new Move();
}

PSORunner::~PSORunner()
{
	delete accelerator;
	delete move;
}

void PSORunner::Initialize(int size, int dim)
{
	vector<double> vtmp;
	vector<int> ptmp;
	for(int j=0;j<dim;j++)
	{
		vtmp.push_back(0);
		ptmp.push_back(0);
		gbest.push_back(0);
	}
	for(int i=0;i<size;i++)
	{
		fpbest.push_back(0);
		velocity.push_back(vtmp);
		pbest.push_back(ptmp);
	}
	fgbest=0;
}

int PSORunner::UpdateBest(vector<vector<int>>& pop,vector<int>& fitvec)
{
	int dim=pop[0].size();
	int maxCombNum=dim*(dim-1)>>1;
	int size=fitvec.size();
	for(int i=0;i<size;i++)
	{
		if(fitvec[i]==maxCombNum)
			return i;
		if(fitvec[i]>fpbest[i])
		{
			fpbest[i]=fitvec[i];
			for(int j=0;j<pop[i].size();j++)
				pbest[i][j]=pop[i][j];
			if(fitvec[i]>fgbest)
			{
				fgbest=fitvec[i];
				for(int j=0;j<pop[i].size();j++)
					gbest[j]=pop[i][j];
			}
		}
	}
	return -1;
}

void PSORunner::clean()
{
	velocity.clear();
	pbest.clear();
	gbest.clear();
	fpbest.clear();
}

int PSORunner::run(vector<vector<int>>& pop, vector<int>& limit)
{
	Initialize(pop.size(),pop[0].size());
	size_t popsize=pop.size();      //size of the population
	int iternum=GetMaxIter();
	//////init fitness vector/////////
	vector<int> pFitVec;
	for(int i=0;i<popsize;i++)
		pFitVec.push_back(0);
	/////////////////////////////////
	GetEvaluator()->run(pop,pFitVec);
	int tmp=UpdateBest(pop, pFitVec);
	if(tmp!=-1)
	{
		clean();
		return tmp;
	}
	for(int i=0;i<iternum;i++)
	{
		accelerator->run(velocity,pop,pbest,gbest,limit);
		move->run(pop, velocity, limit);
		GetEvaluator()->run(pop,pFitVec);
		int tmp=UpdateBest(pop, pFitVec);
		if(tmp!=-1)
		{
			clean();
			return tmp;
		}
	}
	if(fgbest==0)
	{
		clean();
		return -1;
	}
	pop.push_back(gbest);
	clean();
	return popsize;
}